package pers.cz.orm.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pers.cz.common.connect.IConnection;
import pers.cz.common.pub.AbstractEntity;
import utils.ObjUtils;
import utils.UnsafeUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: Jef-orm
 * @description: 抽象sql执行引擎
 * @author: Cheng Zhi
 * @create: 2023-09-02 16:33
 **/
public abstract class BaseSqlEngine implements SqlEngine{

    Logger logger = LoggerFactory.getLogger(BaseSqlEngine.class);

    Connection connection;

    BaseSqlEngine(IConnection iConnection) {
        this.connection = (Connection) iConnection.getConnectin();
    }

    @Override
    public void close() {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                logger.error("close connection fail!", e);
            }
        }
    }

    public <T> List<T> dealResultSet(ResultSet resultSet, Class<T> resultType) {

        if (AbstractEntity.class.isAssignableFrom(resultType)) {
            return (List<T>) dealAbstractEntityResultSet(resultSet, (AbstractEntity) UnsafeUtils.newInstance(resultType));
        } else if (Map.class.isAssignableFrom(resultType)) {
            return (List<T>) dealMapResultSet(resultSet);
        }

        return null;
    }

    /**
     * 将resultSet映射为pojo类
     * @param resultSet
     * @param entity
     * @return
     */
    public List<AbstractEntity> dealAbstractEntityResultSet (ResultSet resultSet, AbstractEntity entity) {
        try {
            Map<String, Class<?>> filedUnderNamesAndType = ObjUtils.getFiledUnderNamesAndType(entity);
            Map<String, Object> fileUnderNameAndValue = new HashMap<>();
            List<AbstractEntity> listEntity = new ArrayList<>();
            while (resultSet.next()) {
                Object[] objects = filedUnderNamesAndType.keySet().toArray();
                for (int i=0; i<objects.length; i++) {
                    String fileldName = (String) objects[i];
                    Class<?> aClass = filedUnderNamesAndType.get(fileldName);
                    Object object = null;
                    // 为什么这样写？因为mysql 驱动中没有适配java.sql.Date和java.util.Date，如果直接赋值会出现Conversion not supported for type java.util.Date异常
                    if (aClass == java.util.Date.class) {
                        // 注意此处获取到的时候如果jdbc串中没有指定时区(serverTimezone=Asia/Shanghai)的话，时间会产生偏移
                        java.sql.Timestamp sqlDate = resultSet.getTimestamp(fileldName);
                        if (sqlDate == null) {
                            continue;
                        }
                        object = new java.util.Date(sqlDate.getTime());
                    } else {
                        object = resultSet.getObject(fileldName, aClass);
                    }

                    fileUnderNameAndValue.put(fileldName, object);
                }

                if (!fileUnderNameAndValue.isEmpty()) {
                    listEntity.add((AbstractEntity) ObjUtils.setFieldForObj(entity, fileUnderNameAndValue, filedUnderNamesAndType));
                }
            }
            return listEntity;

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 将reslutSet映射为Map
     * @param resultSet
     * @return
     */
    public List<Map> dealMapResultSet(ResultSet resultSet) {

        try {
            // 获取数据库字段信息
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            List<String> columnNameList = new ArrayList<>();
            for (int i = 1; i<= columnCount; i++) {
                columnNameList.add(metaData.getColumnName(i));
            }
            List<Map> mapList = new ArrayList<>();
            while (resultSet.next()) {
                Map<String, Object> map = new HashMap<String, Object>();
                for (String columnName: columnNameList) {
                    map.put(columnName, resultSet.getObject(columnName));
                }
                mapList.add(map);
            }

            return mapList;
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;
    }
}
